﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace InDepth2Demo.Chapter6
{
    /// <summary>
    /// 6.3 真实的例子 迭代范围值
    /// </summary>
    public class IteratorExample
    {
        //迭代时刻表中的日期
        public static void ForDemo()
        {
            Timetable timetable = new Timetable();

            for (DateTime day = timetable.StartDate; day <= timetable.EndDate; day = day.AddDays(1))   // 对于时刻表中的每一天
            {
            }

            // 用 foreach
            foreach (DateTime day in timetable.DateRange)
            {
                Console.WriteLine(day);
            }

            IEnumerator<DateTime> enumerator = timetable.DateRange.GetEnumerator();  //上面语句的 完整 foreach 循环逻辑
            while (enumerator.MoveNext())
            {
                DateTime day = enumerator.Current;
                Console.WriteLine(day);
            }
        }

        //迭代文件中的行
        public static void ReadLines()
        {
            using (TextReader reader = File.OpenText($"D:\\1.txt"))
            {
                string line;
                while ((line = reader.ReadLine()) != null)
                {
                    Console.WriteLine(line);
                }
            }
        }

        //使用迭代器块循环遍历文件中的行
        public static IEnumerable<string> ReadLines(string filename)
        {
            using (TextReader reader = File.OpenText(filename))
            {
                string line;
                while ((line = reader.ReadLine()) != null)
                {
                    yield return line;                    // 在对集合进行迭代时，将 行 产生给调用者
                }
            }
        }

        //如果我们想从网络流中读取文本或使用UTF-8以外的编码格式呢? 
        //static IEnumerable<string> ReadLines(TextReader reader)      //这是一个糟糕的方案，将 TextReader 作为参数传递，就不方便清理了 （using、IDispose）

        // 现在只有在有需要的时候才去获取资源，并且那时我们处于IDisposable的上下文中，可以再适当的时候释放资源。
        // 此外，如果对返回值多次调用 GetEnumerator(), 每次都将创建独立的 TextReader。
        static IEnumerable<string> ReadLines(Func<TextReader> provider)
        {
            using (TextReader reader = provider())
            {
                string line;
                while ((line = reader.ReadLine()) != null)
                {
                    yield return line;
                }
            }
        }

        static IEnumerable<string> ReadLines2(string filename)
        {
            return ReadLines(filename, Encoding.UTF8);
        }

        static IEnumerable<string> ReadLines(string filename, Encoding encoding)
        {
            return ReadLines(delegate ()
            {
                return new StreamReader(filename, encoding);
            });
        }

        // 这个简单的示例使用了泛型、匿名方法(捕获了所在方法的参数)和迭代器块。“三缺一的是可空类型，否则就汇集了C#2主要特性的“大四喜”。我曾多次使用过这些代码，它比我们开始时介绍的笨重代码要整洁得多。


        // 使用迭代器块实现LINQ的 WHERE 方法
        public static IEnumerable<T> Where<T>(IEnumerable<T> source, Predicate<T> predicate)
        {
            if (source == null || predicate == null)         //热情地检查参数
            {
                throw new ArgumentNullException();
            }
            return WhereImpl(source, predicate);            //懒惰地处理数据
        }

        public static IEnumerable<T> WhereImpl<T>(IEnumerable<T> source, Predicate<T> predicate)
        {
            foreach (T item in source)
            {
                if (predicate(item))            //检查当前项与谓词是否匹配
                {
                    yield return item;
                }
            }
        }

        public static void Call()
        {
            foreach (string line in ReadLines($"D:\\1.txt"))
            {
                Console.WriteLine(line);
            }
        }

        public static void Call2()
        {
            IEnumerable<string> lines = ReadLines($"D:\\1.txt");
            Predicate<string> predicate = delegate (string line)
            {
                return line.StartsWith("using");
            };
            //bool predicate(string line)
            //{
            //    return line.StartsWith("using");
            //}
            foreach (string line in Where(lines, predicate))
            {
                Console.WriteLine(line);
            }
        }

        //static IEnumerator<ITask> ComputeTotalStockValue(string user, string pass)
        //{
        //    string token = null; 
        //    yield return Arbiter.Receive(false, AuthService.CcrCheck(user, pass), delegate (string t) { token = t; });
        //    IEnumerable<Holding> stocks = nu1l; 
        //    IDictionary<string, decimal> rates = null;
        //    yield return Arbiter.JoinedReceive(false, DbService.CcrGetstockHoldings(token)
        //    StockService.CcrGetRates(token),
        //    delegate (IEnumerable<Holding> s, IDictionary<string, decimal> r) { stocks = s; rates = r; });

        //    OnRequestComplete(ComputeTotal(stocks, rates));
        //}
    }

    //时刻表类
    internal class Timetable
    {
        internal DateTime StartDate = DateTime.Now.AddDays(-3);
        internal DateTime EndDate = DateTime.Now;

        public IEnumerable<DateTime> DateRange          // 原始的循环代码被移动到了时刻表类中，这些代码被封装到一个对“天”进行循环的属性中，并一次生成1个，这样比在业务代码中处理这些“天”要好很多。
        {
            get
            {
                for (DateTime day = StartDate; day <= EndDate; day = day.AddDays(1))
                {
                    yield return day;
                }
            }
        }

    }
}
